namespace Resharper.Abstractions.Actions
{
  using System;
  using JetBrains.Annotations;
  using JetBrains.ReSharper.Feature.Services.Bulbs;
  using JetBrains.ReSharper.Psi;
  using JetBrains.ReSharper.Psi.Tree;

  /// <summary>Defines the <see cref="ProviderContext"/> class.</summary>
  public class ProviderContext
  {
    #region Constructors and Destructors

    /// <summary>Initializes a new instance of the <see cref="ProviderContext"/> class.</summary>
    /// <param name="provider">The provider.</param>
    protected ProviderContext([NotNull] IContextActionDataProvider provider)
    {
      if (provider == null)
      {
        throw new ArgumentNullException("provider");
      }

      this.InternalProvider = provider;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets the caret offset.
    /// </summary>
    public int CaretOffset
    {
      get
      {
        return this.InternalProvider.CaretOffset;
      }
    }

    /// <summary>The provider field.</summary>
    internal IContextActionDataProvider InternalProvider { get; private set; }

    #endregion

    #region Public Methods

    /// <summary>Gets the project path.</summary>
    /// <returns>Returns the project path.</returns>
    public string GetProjectPath()
    {
      var sourceFile = this.InternalProvider.Document.GetPsiSourceFile(this.InternalProvider.Solution);

      var projectFile = sourceFile.ToProjectFile();
      if (projectFile == null)
      {
        return string.Empty;
      }

      var project = projectFile.GetProject();
      if (project == null)
      {
        return string.Empty;
      }

      return project.ProjectFileLocation.ToString();
    }

    /// <summary>Gets the selected text.</summary>
    /// <returns>Returns the selected text.</returns>
    [NotNull]
    public string GetSelectedText()
    {
      var treeNode = this.InternalProvider.SelectedElement;

      return treeNode != null ? treeNode.GetText() : string.Empty;
    }

    #endregion

    #region Methods

    /// <summary>Gets the selected tree node.</summary>
    /// <returns>Returns the selected tree node.</returns>
    [CanBeNull]
    internal ITreeNode GetSelectedTreeNode()
    {
      return this.InternalProvider.SelectedElement;
    }

    /// <summary>Gets the selected element.</summary>
    /// <returns>Returns the selected element.</returns>
    [CanBeNull]
    internal T InternalGetSelectedElement<T>() where T : class, ITreeNode
    {
      return this.InternalProvider.GetSelectedElement<T>(true, true);
    }

    #endregion
  }
}